闲话 22.11.25
闲话
完了下面杂题的字号太大了
这段闲话似乎需要在调小下面字号的情况下写(
不知道为什么感觉这边需要变一个画风
?中午还在想写啥 下午就不知道该从何说起了
但一般而言从不知从何说起说起是比较不错的开头
因为我想扯闲天 所以没什么关系
旁边有人问我想干啥
我说我想扯闲天 然后敲完了上面的话
最近感觉上入冬了(
晚上去吃饭的路上裹着羽绒服 紧紧揣着兜
然后看着路灯
总感觉这种感觉之前有过
那时候似乎在下雪
然后就吐槽为什么不下雪
然后被吐槽了白色相簿的季节
是想要的吐槽(
嘛感觉我这边大概上不会有什么心态上的变化
有也不会太大
反正生活都要继续嘛
完了开始沉重了
那就扯开吧
某人看了一点小圆剧场版
然后跟我剧透某人变魔女了
我的回答:肯定是知道内情的人才会出现这种情况,所以是qb(
“你说得对”
昨天为什么没有闲话?
打 mc 打得很嗨
今天为什么有闲话?
不让打 mc 了
感觉上如果缺了闲话会在摘要里补上
嘿打完刚才那句话自动补上了个句号
然后觉得不是很对劲给他删了
就这种写法我是比较喜欢的(
Why so serious?
这种日常感是很重要的呢!
感觉上我最重视的永远是日常感
尤其是在对作品的选择上
小圆这种显然就不在其中了(
似乎写完了
所以下面的标题字号可以调回来了(
草生 没调过来
现在好了 如果有人刚才看到了小小的标题就知道我说的是真的了(
仍然是惯例的杂题!
进行一个闲话的补
对于两个串S1、S2,如果能够将S1的一个后缀移动到开头后变成S2,就称S1和S2循环相同。例如串ababba和串abbaab是循环相同的。
给出一个长度为n的串S,求满足下面条件的最大的L:
- S的L前缀和S的L后缀是循环相同的。
。
考虑一个串是满足条件的当且仅当其形如 ,其中 。容易发现我们需要迅速求出删掉原串两侧左右两侧 border 后()的新最长 border 长度。如果这玩意是道子串查询 border 长度的题就没意思了。而且不迅速(
考虑我们需要求的是删除原串两侧定长度子串后剩余串的 border。这玩意可以递推。
设 为原串两侧删除 长度子串后串的 border 长度。初值为 因为串没了。
每一次向左右两侧拓展一个字符,border 长度最长增加 2。朴素地验证当前长度()是否是一个 border 的长度,不满足就自减 1 后接着查询。
使用哈希做到 dp 出每个位置的 border 长度。
随后找到原串所有 border 就做完了。
总时间复杂度 。
code
#include <bits/stdc++.h>
#define rep(i,s,t) for (int i = (s), i##END = (t) + 1; i < i##END; ++ i)
#define pre(i,s,t) for (int i = (s), i##END = (t) - 1; i > i##END; -- i)
using namespace std;
const int N = 1e6 + 10, bse = 131, mod = 1e9 + 3579;
int n, ans, nxt[N], f[N], hsh[N], pw[N];
char ch[N];
int get(int l, int r) { return (1ll * hsh[r] - 1ll * hsh[l - 1] * pw[r - l + 1] % mod + mod) % mod; }
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> ch + 1; pw[0] = 1;
rep(i,1,n) hsh[i] = (1ll * hsh[i - 1] * bse + ch[i]) % mod, pw[i] = 1ll * pw[i - 1] * bse % mod;
for (int i = 2, j = 0; i <= n; ++ i) {
while (j and ch[j + 1] != ch[i]) j = nxt[j];
if (ch[j + 1] == ch[i]) ++ j;
nxt[i] = j;
}
int st = (n >> 1) + (n & 1);
f[st] = 0;
pre(i, st-1, 0) {
f[i] = min(f[i + 1] + 2, (n - (i << 1)) >> 1);
while (f[i] and get(i + 1, i + f[i]) != get(n - i - f[i] + 1, n - i)) -- f[i];
}
for (int p = nxt[n]; p; p = nxt[p]) if (p < st) ans = max(ans, p + f[p]);
cout << ans << '\n';
}
给定一个长度为 的字符串 。定义 子串表示 。显然的, 子串= ,并且有 个 子串。
对于每一个 子串 ,试找出最大长度的字符串 ,使得 是 的前缀和后缀且 的 长度为奇数。
和上面那题的做法一样。
初值看着设成 1/-1,然后每次自增 2。验证当前情况下如果不满足条件就自减 2,直到减成 - 1。
这题 *2700 不是很认可。
code
#include <bits/stdc++.h>
#define rep(i,s,t) for (int i = (s), i##END = (t) + 1; i < i##END; ++ i)
#define pre(i,s,t) for (int i = (s), i##END = (t) - 1; i > i##END; -- i)
using namespace std;
const int N = 1e6 + 10, bse = 131, mod = 1e9 + 3579;
int n, ans, f[N], hsh[N], pw[N];
char ch[N];
int get(int l, int r) { return (1ll * hsh[r] - 1ll * hsh[l - 1] * pw[r - l + 1] % mod + mod) % mod; }
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> ch + 1; pw[0] = 1;
rep(i,1,n) hsh[i] = (1ll * hsh[i - 1] * bse + ch[i]) % mod, pw[i] = 1ll * pw[i - 1] * bse % mod;
int st = (n >> 1) + (n & 1);
if (n & 1) f[st] = -1;
else f[st] = (ch[st] == ch[st + 1] ? 1 : -1);
pre(i, st-1, 0) {
f[i] = f[i + 1] + 2;
while (f[i] > -1 and get(i, i + f[i] - 1) != get(n - i + 1 - f[i] + 1, n - i + 1)) f[i] -= 2;
} rep(i,1,st) cout << f[i] << ' ';
}
给定长度为 的序列 ,求满足 的二元组 的个数。
,。
没错,做完上面那题之后看到的。
考虑怎么维护三个性质。
我们一点点删掉不满足条件的 ,最开始 ,所有 都满足条件。
按 先排个序,然后 j 倒着扫统计。首先把所有满足 的 都扔掉。然后查询小于等于 的 的个数作为答案。
然后做完了。总时间复杂度 。
*1900 正常。紫色的不是很认可。
code
#include <bits/stdc++.h>
#define rep(i,s,t) for (int i = (s), i##END = (t) + 1; i < i##END; ++ i)
#define pre(i,s,t) for (int i = (s), i##END = (t) - 1; i > i##END; -- i)
using namespace std;
const int N = 2e5 + 10;
int n, a[N], id[N];
long long ans;
struct BIT {
int Index[N];
void add(int p, int v) { for (; p <= n; p += p & -p) Index[p] += v; }
int qry(int p) { int ret = 0; for (; p; p ^= p & -p) ret += Index[p]; return ret; }
} B;
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n; rep(i,1,n) cin >> a[i], id[i] = i;
sort(id + 1, id + 1 + n, [&](const int &x, const int &y){ return a[x] < a[y]; });
int ptr = 1;
rep(i,1,n) B.Index[i] = (i & -i);
rep(j,1,n) {
while (ptr <= n and a[id[ptr]] < j) B.add(id[ptr], -1), ++ ptr;
ans += B.qry(min(j - 1, a[j]));
} cout << ans << '\n';
}
题面长,不搬。
首先很容易发现一个东西
就是你应该用生成函数去刻画这个东西(
而且我们只需要去刻画这个叶子
记 为树 上的叶子组成的多重集对应的生成函数。具体地,
然后记 为一个多项式 中最低次项。 这种样子的。
然后可以刻画了。
挺长的
然后我们观察两次合并会产生些什么效果。
为了不让式子变长,我们记第一次换的叶子是 ,第二次换的叶子是 。
那两次换叶子的功效就是
挺好看
这告诉我们其实两次换叶子是等价的,顺序不重要。
然后我们假设深度为 的叶子被换了 次后换完。
有
然后就是
看到 取对数:
对比系数得到
注意这里是 的 次方,而不是 的 次方。因此最后 的指数是 。
做完了。总时间复杂度 。
还没实现。晚点再说。
upd: 实现了 写的是枚举因子的写法所以是
注意枚举因子时 时不要统计两次。
code
#include <bits/stdc++.h>
#define rep(i,s,t) for (int i = (s), i##END = (t) + 1; i < i##END; ++ i)
#define pre(i,s,t) for (int i = (s), i##END = (t) - 1; i > i##END; -- i)
using namespace std;
int n, m, t1, t2, ans[N];
unsigned a[N];
vector<int> g[N];
void dfs(int u, int fa, int dep) {
if (g[u].size() == 1) a[dep] = (1ll * a[dep] - 1 + mod) % mod;
for (auto v : g[u]) if (v != fa) dfs(v, u, dep + 1);
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
rep(i,2,n) cin >> t1 >> t2, g[t1].emplace_back(t2), g[t2].emplace_back(t1);
dfs(1, 0, 0); a[0] ++;
poly f(a, a + m + 1);
f = f.ln();
rep(i,1,m) f[i] = (mod - 1ll * f[i]) % mod;
rep(k,1,m) {
ans[k] = f[k];
for (int i = 1, j; i * i <= k; ++ i) if (k % i == 0) {
j = k / i;
if (i != k) ans[k] = (ans[k] + 1ll * ( (j & 1) ? mod - 1 : 1 ) * ans[i] % mod * math::ginv(j)) % mod;
if (i * i != k) {
swap(i, j);
if (i != k) ans[k] = (ans[k] + 1ll * ( (j & 1) ? mod - 1 : 1 ) * ans[i] % mod * math::ginv(j)) % mod;
swap(i, j);
}
}
}
rep(i,1,m) ans[i] = (ans[i - 1] + ans[i]) % mod;
rep(i,1,m) cout << ans[i] << '\n';
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat221125.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)